#include "wprocess.h"
#include "fs.h"
#include "str.h"
//#include "charset.h"
#include "ithread.h"
#include "xtime.h"
#include <tlhelp32.h>
#include <winternl.h>
#include <psapi.h>
#include <algorithm>
#include <thread>

namespace log4x
{

wprocess::wprocess()
{
}


wprocess::~wprocess()
{
}


int
wprocess::pid()
{
    return (int)GetCurrentProcessId();;
}

int
wprocess::pids(const string& pname, vector<int>& pids, vector<string>& cmdLines)
{
    string name = pname;
    if (string::npos == pname.find(".exe"))
    {
        name += ".exe";
    }

    PROCESSENTRY32 entry32;
    entry32.dwSize  = sizeof(PROCESSENTRY32);
    BOOL   bRet     = FALSE;
    HANDLE hProcess = NULL;

    hProcess = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
    if (!hProcess)
    {
        return -1;
    }

    bRet = Process32First(hProcess, &entry32);
    if (!bRet)
    {
        return -1;
    }

    while (bRet)
    {
        char buf[512] = {0};
        _snprintf_s(buf, sizeof(buf), "%s", entry32.szExeFile);
        if (buf == name)
        {
            pids.push_back((uint32_t)entry32.th32ProcessID);
            cmdLines.push_back(cmdline(entry32.th32ProcessID));
        }

        bRet = Process32Next(hProcess, &entry32);
        /* std::this_thread::sleep_for(std::chrono::nanoseconds(1)); */
    }

    ::CloseHandle(hProcess);
    return 0;
}

int
wprocess::pids(const string& workdir, map<int, string>& procs)
{
    PROCESSENTRY32 entry32;
    entry32.dwSize  = sizeof(PROCESSENTRY32);
    BOOL   bRet     = FALSE;
    HANDLE hProcess = NULL;

    hProcess = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
    if (!hProcess)
    {
        return -1;
    }

    bRet = Process32First(hProcess, &entry32);
    if (!bRet)
    {
        return -1;
    }

    while (bRet)
    {
        do
        {
            if (entry32.th32ProcessID == (DWORD)this->pid())
            {
                break;
            }

            string abspath = fs::absolute_path(workdir);
            string ppath   = wprocess::ppath(entry32.th32ProcessID);
            if (ppath.empty() || ppath.find(abspath) == string::npos)
            {
                break;
            }
            procs[(int)entry32.th32ProcessID] = ppath;
        }
        while (0);
        bRet = Process32Next(hProcess, &entry32);
    }

    ::CloseHandle(hProcess);
    return 0;
}

string
wprocess::ppath(int pid)
{
    TCHAR szModName[MAX_PATH] = {0};

    if (-1 == pid)
    {
        if (!GetModuleFileNameA(NULL, szModName, sizeof(szModName) - 1))
        {
            return "";
        }
    }
    else
    {
        HANDLE hProcess;

        /* Get a list of all the modules in this process. */
        hProcess = OpenProcess(PROCESS_QUERY_INFORMATION |
                               PROCESS_VM_READ,
                               FALSE, pid);
        if (NULL == hProcess)
        {
            return "";
        }

#if __MINGW32__
        /**
         * EnumProcessModules/GetModuleFileNameEx
         * x32位程序获取64位运行进程路径会失败,返回ERROR_PARTIAL_COPY(299)错误
         *
         * 根据官方的说法:
         * For the best results use the following table to convert paths.
         *
         * Windows 2000       = GetModuleFileNameEx()
         * Windows XP x32     = GetProcessImageFileName()
         * Windows XP x64     = GetProcessImageFileName()
         * Windows Server2003 = GetProcessImageFileName()
         * Windows Vista      = QueryFullProcessImageName()
         * Windows 7          = QueryFullProcessImageName()
         */
        HMODULE hMods[1024];
        DWORD cbNeeded;
        unsigned int i;
        if (EnumProcessModules(hProcess, hMods, sizeof(hMods), &cbNeeded))
        {
            for (i = 0; i < (cbNeeded / sizeof(HMODULE)); i++)
            {
                /* Get the full path to the module's file. */
                if (GetModuleFileNameEx(hProcess, hMods[i], szModName,
                                        sizeof(szModName) / sizeof(TCHAR)))
                {
                    if (".exe" == fs::extension(szModName))
                    {
                        break;
                    }
                }
            }
        }
        else
        {
            int res = GetLastError();
            if (ERROR_PARTIAL_COPY != res)
            {
            }
        }
#else
        DWORD size = MAX_PATH;
        if (!QueryFullProcessImageName(hProcess, 0, szModName, &size))
        {
            int res = GetLastError();
            if (ERROR_GEN_FAILURE != res)
            {
            }
        }
#endif
        CloseHandle(hProcess);
    }

    string filename = szModName;
    fs::path_to_unix(filename);
    return filename;
}

int
wprocess::system(const string& path_cmd)
{
    string cmd = path_cmd;
    fs::path_to_win(cmd);

    ::system(cmd.c_str());
    return 0;
}

int
wprocess::system(const string& path_cmd, string& result)
{
    string cmd = path_cmd;
    fs::path_to_win(cmd);

    char  buffer[512] = {0};
    FILE* fp = NULL;

    /* Run DIR so that it writes its output to a pipe. Open this
     * pipe with read text attribute so that we can read it
     * like a text file.
     */
    if (!(fp = _popen(cmd.c_str(), "rt")))
    {
        return -1;
    }

    /* Read pipe until end of file, or an error occurs. */
    while (fgets(buffer, 512, fp))
    {
        result += buffer;
    }

    /* Close pipe and print return value of fp. */
    if (feof(fp))
    {
        _pclose(fp);
    }
    else
    {
    }
    return 0;
}

typedef
NTSTATUS(WINAPI *pfnNtWow64QueryInformationProcess64)(
    HANDLE  ProcessHandle,
    UINT32  ProcessInformationClass,
    PVOID   ProcessInformation,
    UINT32  ProcessInformationLength,
    UINT32* ReturnLength);

typedef
NTSTATUS(WINAPI *pfnNtWow64ReadVirtualMemory64)(
    HANDLE  ProcessHandle,
    PVOID64 BaseAddress,
    PVOID   BufferData,
    UINT64  BufferLength,
    PUINT64 ReturnLength);

typedef
NTSTATUS(WINAPI *pfnNtQueryInformationProcess)(
    HANDLE  ProcessHandle,
    ULONG   ProcessInformationClass,
    PVOID   ProcessInformation,
    UINT32  ProcessInformationLength,
    UINT32* ReturnLength);

template <typename T>
struct _UNICODE_STRING_T
{
    WORD Length;
    WORD MaximumLength;
    T Buffer;
};

template <typename T>
struct _LIST_ENTRY_T
{
    T Flink;
    T Blink;
};

template <typename T, typename NGF, int A>
struct _PEB_T
{
    typedef T type;

    union
    {
        struct
        {
            BYTE InheritedAddressSpace;
            BYTE ReadImageFileExecOptions;
            BYTE BeingDebugged;
            BYTE BitField;
        };
        T dummy01;
    };
    T     Mutant;
    T     ImageBaseAddress;
    T     Ldr;
    T     ProcessParameters;
    T     SubSystemData;
    T     ProcessHeap;
    T     FastPebLock;
    T     AtlThunkSListPtr;
    T     IFEOKey;
    T     CrossProcessFlags;
    T     UserSharedInfoPtr;
    DWORD SystemReserved;
    DWORD AtlThunkSListPtr32;
    T     ApiSetMap;
    T     TlsExpansionCounter;
    T     TlsBitmap;
    DWORD TlsBitmapBits[2];
    T     ReadOnlySharedMemoryBase;
    T     HotpatchInformation;
    T     ReadOnlyStaticServerData;
    T     AnsiCodePageData;
    T     OemCodePageData;
    T     UnicodeCaseTableData;
    DWORD NumberOfProcessors;
    union
    {
        DWORD NtGlobalFlag;
        NGF dummy02;
    };
    LARGE_INTEGER CriticalSectionTimeout;

    T     HeapSegmentReserve;
    T     HeapSegmentCommit;
    T     HeapDeCommitTotalFreeThreshold;
    T     HeapDeCommitFreeBlockThreshold;
    DWORD NumberOfHeaps;
    DWORD MaximumNumberOfHeaps;
    T     ProcessHeaps;
    T     GdiSharedHandleTable;
    T     ProcessStarterHelper;
    T     GdiDCAttributeList;
    T     LoaderLock;
    DWORD OSMajorVersion;
    DWORD OSMinorVersion;
    WORD  OSBuildNumber;
    WORD  OSCSDVersion;
    DWORD OSPlatformId;
    DWORD ImageSubsystem;
    DWORD ImageSubsystemMajorVersion;
    T     ImageSubsystemMinorVersion;
    T     ActiveProcessAffinityMask;
    T     GdiHandleBuffer[A];
    T     PostProcessInitRoutine;
    T     TlsExpansionBitmap;
    DWORD TlsExpansionBitmapBits[32];
    T     SessionId;

    ULARGE_INTEGER AppCompatFlags;
    ULARGE_INTEGER AppCompatFlagsUser;

    T     pShimData;
    T     AppCompatInfo;
    _UNICODE_STRING_T<T> CSDVersion;
    T     ActivationContextData;
    T     ProcessAssemblyStorageMap;
    T     SystemDefaultActivationContextData;
    T     SystemAssemblyStorageMap;
    T     MinimumStackCommit;
    T     FlsCallback;

    _LIST_ENTRY_T<T> FlsListHead;

    T     FlsBitmap;
    DWORD FlsBitmapBits[4];
    T     FlsHighIndex;
    T     WerRegistrationData;
    T     WerShipAssertPtr;
    T     pContextData;
    T     pImageHeaderHash;
    T     TracingFlags;
    T     CsrServerReadOnlySharedMemoryBase;
};

template <typename T>
struct _STRING_T
{
    WORD Length;
    WORD MaximumLength;
    T    Buffer;
};

template <typename T>
struct _RTL_DRIVE_LETTER_CURDIR_T
{
    WORD         Flags;
    WORD         Length;
    ULONG        TimeStamp;
    _STRING_T<T> DosPath;
};

template <typename T>
struct _CURDIR_T
{
    _UNICODE_STRING_T<T> DosPath;
    T			         Handle;
};

template <typename T>
struct _RTL_USER_PROCESS_PARAMETERS_T
{
    ULONG MaximumLength;
    ULONG Length;
    ULONG Flags;
    ULONG DebugFlags;
    T     ConsoleHandle;
    ULONG ConsoleFlags;
    T     StandardInput;
    T     StandardOutput;
    T     StandardError;

    _CURDIR_T<T>         CurrentDirectory;
    _UNICODE_STRING_T<T> DllPath;
    _UNICODE_STRING_T<T> ImagePathName;
    _UNICODE_STRING_T<T> CommandLine;

    T     Environment;
    ULONG StartingX;
    ULONG StartingY;
    ULONG CountX;
    ULONG CountY;
    ULONG CountCharsX;
    ULONG CountCharsY;
    ULONG FillAttribute;
    ULONG WindowFlags;
    ULONG ShowWindowFlags;

    _UNICODE_STRING_T<T> WindowTitle;
    _UNICODE_STRING_T<T> DesktopInfo;
    _UNICODE_STRING_T<T> ShellInfo;
    _UNICODE_STRING_T<T> RuntimeData;
    _RTL_DRIVE_LETTER_CURDIR_T<T> CurrentDirectores[32];
    ULONG EnvironmentSize;
};

typedef _PEB_T<DWORD, DWORD64, 34> _PEB32;
typedef _PEB_T<DWORD64, DWORD, 30> _PEB64;
typedef _RTL_USER_PROCESS_PARAMETERS_T<UINT32> _RTL_USER_PROCESS_PARAMETERS32;
typedef _RTL_USER_PROCESS_PARAMETERS_T<UINT64> _RTL_USER_PROCESS_PARAMETERS64;

typedef struct _PROCESS_BASIC_INFORMATION64
{
    NTSTATUS ExitStatus;
    UINT32   Reserved0;
    UINT64   PebBaseAddress;
    UINT64   AffinityMask;
    UINT32   BasePriority;
    UINT32   Reserved1;
    UINT64   UniqueProcessId;
    UINT64   InheritedFromUniqueProcessId;
} PROCESS_BASIC_INFORMATION64;

typedef struct _PROCESS_BASIC_INFORMATION32
{
    NTSTATUS ExitStatus;
    UINT32   PebBaseAddress;
    UINT32   AffinityMask;
    UINT32   BasePriority;
    UINT32   UniqueProcessId;
    UINT32   InheritedFromUniqueProcessId;
} PROCESS_BASIC_INFORMATION32;


typedef struct _PEB_INFO
{
    UINT64 ImageBaseAddress;
    UINT64 Ldr;
    UINT64 ProcessHeap;
    UINT64 ProcessParameters;
    UINT64 Environment;
} PEBInfo, *PPEBInfo;

static string
wstring2string(wstring wstr)
{
    string result;

    /* /获取缓冲区大小, 并申请空间，缓冲区大小事按字节计算的 */
    int len = WideCharToMultiByte(CP_ACP, 0, wstr.c_str(), (int)wstr.size(), NULL, 0, NULL, NULL);
    char* buffer = new char[len + 1];

    /* 宽字节编码转换成多字节编码 */
    WideCharToMultiByte(CP_ACP, 0, wstr.c_str(), (int)wstr.size(), buffer, len, NULL, NULL);
    buffer[len] = '\0';

    /* 删除缓冲区并返回值 */
    result.append(buffer);
    delete[] buffer;
    return result;
}

#if 0
static wstring
string2wstring(string str)
{
    wstring result;

    /* 获取缓冲区大小，并申请空间，缓冲区大小按字符计算 */
    int len = MultiByteToWideChar(CP_ACP, 0, str.c_str(), str.size(), NULL, 0);
    wchar_t* buffer = new wchar_t[len + 1];

    /* 多字节编码转换成宽字节编码 */
    MultiByteToWideChar(CP_ACP, 0, str.c_str(), str.size(), buffer, len);
    buffer[len] = '\0';

    /* 删除缓冲区并返回值 */
    result.append(buffer);
    delete[] buffer;
    return result;
}
#endif

BOOL
Is64bitSystem()
{
    SYSTEM_INFO si;
    GetNativeSystemInfo(&si);
    if (si.wProcessorArchitecture == PROCESSOR_ARCHITECTURE_AMD64 ||
            si.wProcessorArchitecture == PROCESSOR_ARCHITECTURE_IA64)
    {
        return TRUE;
    }
    else
    {
        return FALSE;
    }
}

static int
GetProcessCmdLine0(HANDLE hProcess, string& cmdLine)
{
    PEBInfo PebInfo;
    memset(&PebInfo, 0, sizeof(PEBInfo));

    HMODULE NtdllModule = GetModuleHandle(TEXT("ntdll.dll"));
    pfnNtQueryInformationProcess NtQueryInformationProcess = (pfnNtQueryInformationProcess)GetProcAddress(NtdllModule,
            "NtQueryInformationProcess");

    /* 0. 获取进程环境块的地址 */
    PROCESS_BASIC_INFORMATION32 pbi;
    memset(&pbi, 0, sizeof(PROCESS_BASIC_INFORMATION32));

    UINT32  ReturnLength = 0;
    NTSTATUS status = NtQueryInformationProcess(hProcess,
                      ProcessBasicInformation, &pbi, (UINT32)sizeof(pbi), (UINT32*)&ReturnLength);

    if (!NT_SUCCESS(status))
    {
        return -1;
    }

    /* 1. 获取进程环境块 */
    _PEB32 Peb;
    if (!ReadProcessMemory(hProcess, (PVOID)pbi.PebBaseAddress, &Peb, sizeof(_PEB32), NULL))
    {
        return -1;
    }

    /* 2. 获取PEB块的参数块 */
    _RTL_USER_PROCESS_PARAMETERS32 Parameters32;
    if (!ReadProcessMemory(hProcess, (PVOID)Peb.ProcessParameters, &Parameters32, sizeof(_RTL_USER_PROCESS_PARAMETERS32), NULL))
    {
        return -1;
    }

    /* 3. 获取命令行 */
    WCHAR* CommandLine = new WCHAR[Parameters32.CommandLine.Length];
    memset(CommandLine, 0, Parameters32.CommandLine.Length * sizeof(WCHAR));
    if (!ReadProcessMemory(hProcess, (PVOID)Parameters32.CommandLine.Buffer, CommandLine, Parameters32.CommandLine.Length, NULL))
    {
        return -1;
    }

    /* 4. WCHAR 转 char */
    cmdLine = wstring2string(CommandLine);
    delete[] CommandLine;
    return 0;
}

static int
GetProcessCmdLine1(HANDLE hProcess, string& cmdLine)
{
    PEBInfo PebInfo;
    memset(&PebInfo, 0, sizeof(PEBInfo));

    HMODULE NtdllModule = GetModuleHandle(TEXT("ntdll.dll"));
    pfnNtWow64QueryInformationProcess64 NtWow64QueryInformationProcess64 = (pfnNtWow64QueryInformationProcess64)GetProcAddress(NtdllModule,
            "NtWow64QueryInformationProcess64");

    pfnNtWow64ReadVirtualMemory64 NtWow64ReadVirtualMemory64 = (pfnNtWow64ReadVirtualMemory64)GetProcAddress(NtdllModule, "NtWow64ReadVirtualMemory64");

    /* 0. 获取进程环境块的地址 */
    PROCESS_BASIC_INFORMATION64 pbi;
    memset(&pbi, 0, sizeof(PROCESS_BASIC_INFORMATION64));

    UINT64 ReturnLength = 0;
    NTSTATUS status = NtWow64QueryInformationProcess64(hProcess, ProcessBasicInformation, &pbi, (UINT32)sizeof(pbi), (UINT32*)&ReturnLength);
    if (!NT_SUCCESS(status))
    {
        return -1;
    }

    /* 1. 获取进程环境块(注意: mingw32测试不通过, msvc32测试OK) */
    _PEB64 Peb;
    status = NtWow64ReadVirtualMemory64(hProcess, (PVOID64)pbi.PebBaseAddress, &Peb, sizeof(_PEB64), &ReturnLength);
    if (!NT_SUCCESS(status))
    {
        return -1;
    }

    /* 2. 获取PEB块的参数块 */
    _RTL_USER_PROCESS_PARAMETERS64 Parameters64;
    status = NtWow64ReadVirtualMemory64(hProcess, (PVOID64)Peb.ProcessParameters, &Parameters64, sizeof(_RTL_USER_PROCESS_PARAMETERS64), &ReturnLength);
    if (!NT_SUCCESS(status))
    {
        return -1;
    }

    /* 3. 获取命令行 */
    WCHAR* CommandLine = new WCHAR[Parameters64.CommandLine.Length];
    memset(CommandLine, 0, Parameters64.CommandLine.Length * sizeof(WCHAR));
    status = NtWow64ReadVirtualMemory64(hProcess, (PVOID64)Parameters64.CommandLine.Buffer, CommandLine, Parameters64.CommandLine.Length, NULL);
    if (!NT_SUCCESS(status))
    {
        return -1;
    }

    /* 4. WCHAR 转 char */
    cmdLine = wstring2string(CommandLine);
    delete[] CommandLine;
    return 0;
}

static int
GetProcessCmdLine2(HANDLE hProcess, string& cmdLine)
{
    PEBInfo PebInfo;
    memset(&PebInfo, 0, sizeof(PEBInfo));

    HMODULE NtdllModule = GetModuleHandle(TEXT("ntdll.dll"));
    pfnNtQueryInformationProcess NtQueryInformationProcess = (pfnNtQueryInformationProcess)GetProcAddress(NtdllModule,
            "NtQueryInformationProcess");

    PROCESS_BASIC_INFORMATION64 pbi;
    memset(&pbi, 0, sizeof(PROCESS_BASIC_INFORMATION64));
    UINT32  ReturnLength = 0;

    /* 0. 获取进程环境块的地址 */
    NTSTATUS status = NtQueryInformationProcess(hProcess, ProcessBasicInformation, &pbi, (UINT32)sizeof(pbi), (UINT32*)&ReturnLength);
    if (!NT_SUCCESS(status))
    {
        return -1;
    }

    /* 1. 获取进程环境块 */
    _PEB64 Peb;
    if (!ReadProcessMemory(hProcess, (PVOID)pbi.PebBaseAddress, &Peb, sizeof(_PEB64), NULL))
    {
        return -1;
    }

    /* 2. 获取PEB块的参数块 */
    _RTL_USER_PROCESS_PARAMETERS64 Parameters64;
    if (!ReadProcessMemory(hProcess, (PVOID)Peb.ProcessParameters, &Parameters64, sizeof(_RTL_USER_PROCESS_PARAMETERS64), NULL))
    {
        return -1;
    }

#if 0
    BYTE* Environment = new BYTE[Parameters64.EnvironmentSize * 2];
    status = ReadProcessMemory(hProcess, (PVOID)Parameters64.Environment, Environment, Parameters64.EnvironmentSize, NULL);

    PebInfo.ImageBaseAddress = Peb.ImageBaseAddress;
    PebInfo.Ldr = Peb.Ldr;
    PebInfo.ProcessHeap = Peb.ProcessHeap;
    PebInfo.ProcessParameters = Peb.ProcessParameters;
    PebInfo.Environment = Parameters64.Environment;

    printf("ImageBaseAddress:0x%x\r\n",  PebInfo.ImageBaseAddress);
    printf("Ldr:0x%x\r\n",               PebInfo.Ldr);
    printf("ProcessHeap:0x%x\r\n",       PebInfo.ProcessHeap);
    printf("ProcessParameters:0x%x\r\n", PebInfo.ProcessParameters);
    printf("Environment:0x%x\r\n",       PebInfo.Environment);

    while (Environment != NULL)
    {
        char* v1 = NULL;
        int DataLength = WideCharToMultiByte(CP_ACP, NULL, (WCHAR*)Environment, -1, NULL, 0, NULL, FALSE);
        v1 = new char[DataLength + 1];
        WideCharToMultiByte(CP_OEMCP, NULL, (WCHAR*)Environment, -1, v1, Parameters64.EnvironmentSize * 2, NULL, FALSE);
        printf("%s\r\n", v1);

        /* 指针移动到字符串末尾 */
        while (*(WCHAR*)Environment != '\0')
        {
            Environment += 2;
        }
        Environment += 2;

        /* 是否是最后一个字符串 */
        if (*Environment == '\0')
        {
            break;
        }
    }
#endif

    /* 3. 获取命令行 */
    WCHAR* CommandLine = new WCHAR[Parameters64.CommandLine.Length];
    memset(CommandLine, 0, Parameters64.CommandLine.Length * sizeof(WCHAR));
    if (!ReadProcessMemory(hProcess, (PVOID)Parameters64.CommandLine.Buffer, CommandLine, Parameters64.CommandLine.Length, NULL))
    {
        return -1;
    }

    /* 4. WCHAR 转 char */
    cmdLine = wstring2string(CommandLine);
    delete[] CommandLine;

#if 0
    BYTE* ImagePathName = new BYTE[Parameters64.ImagePathName.Length];
    status = ReadProcessMemory(hProcess, (PVOID)Parameters64.ImagePathName.Buffer, ImagePathName, Parameters64.ImagePathName.Length, NULL);
    if (ImagePathName != NULL)
    {
        char* v1 = NULL;
        int DataLength = WideCharToMultiByte(CP_ACP, NULL, (WCHAR*)ImagePathName, -1, NULL, 0, NULL, FALSE);
        v1 = new char[DataLength];
        memset(v1, 0, DataLength);
        WideCharToMultiByte(CP_OEMCP, NULL, (WCHAR*)ImagePathName, -1, v1, Parameters64.ImagePathName.Length, NULL, FALSE);
    }
#endif
    return 0;
}

string
wprocess::cmdline(int pid)
{
    if (-1 == pid)
    {
        return ::GetCommandLine();
    }

    HANDLE hProcess = OpenProcess(PROCESS_QUERY_INFORMATION | PROCESS_VM_READ, FALSE, pid);
    if (hProcess == NULL)
    {
        return "";
    }

    int system  = Is64bitSystem() ? 64 : 32;
#ifdef _WIN64
    int current = 64;
#else
    int current = 32;
#endif

    /**
     * IsWow64Process说明：
     * 确定指定进程是否运行在64位操作系统的32环境(Wow64)下
     * 如果该进程是32位进程, 运行在64操作系统下, 该值为True, 否则为False
     * 如果该进程是一个64位应用程序, 运行在64位系统上, 该值也被设置为False
     * 如果该进程运行在32位系统下, 该值会被设置为False
     */
    BOOL bTarget = FALSE;
    IsWow64Process(hProcess, &bTarget);
    int target = bTarget ? 32 : 64;

    /**
     * 系统 | 本程序 | 目标程序 | type
     * 32   | 32     | 32       | 0
     * 32   | 32     | 64       | x
     * 32   | 64     | 32       | x
     * 32   | 64     | 64       | x
     *
     * 64   | 32     | 32       | 0
     * 64   | 32     | 64       | 1
     * 64   | 64     | 32       | 2
     * 64   | 64     | 64       | 2
     */

    string result = "";
    if (
        (32 == system && 32 == current && 32 == target) ||
        (64 == system && 32 == current && 32 == target))
    {
        GetProcessCmdLine0(hProcess, result);
    }
    else if (
        (64 == system && 32 == current && 64 == target))
    {
#ifdef __MINGW32__
#else
        GetProcessCmdLine1(hProcess, result);
#endif
    }
    else if (
        (64 == system && 64 == current && 32 == target) ||
        (64 == system && 64 == current && 64 == target))

    {
        GetProcessCmdLine2(hProcess, result);
    }
    else
    {
        GetProcessCmdLine0(hProcess, result);
    }

    CloseHandle(hProcess);
    return result;
}

}
